home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / comm / cnet / ansi_pack.lha / ANSI_Rexx < prev    next >
Text File  |  1996-12-04  |  35KB  |  721 lines

  1. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2.           Using & Interpreting ANSI Codes in Your ARexx Creations!      v1.00
  3. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  4.  
  5.    Alright, a few of you out there(you know who you are), have been throwing
  6. hints my way about the actual USAGE of ANSI codes in ARexx for CNet Amiga,
  7. so let's have some fun!
  8.  
  9.    Of all the available ANSI codes, the following can(and SHOULD) be used to
  10. the hilt in anything you write! ;-)
  11.  
  12.         ~[?;?;?m   ~[?;?H   ~[?A   ~[?B   ~[?C   ~[?D   ~[s   ~[u
  13.  
  14.    These codes, coupled with some CNet ARexx Primitives(namely GETCHAR,
  15. MAYGETCHAR, TRANSMIT, and SENDSTRING) are all you really need to get your
  16. own programs using ANSI both effectively and efficiently. It should also be
  17. noted that the majority of the CNet Primitives used in this discussion are
  18. also part of the "ABBEREXX" standard, to which MANY Amiga BBS programs
  19. adhere to, so these explanations may prove useful for Non-CNet SysOps as
  20. well.
  21.  
  22.    Before continuing, please take a moment to install the following little
  23. scripts, which I have found to be extremely helpful in the creation of my
  24. ARexx projects, and you might as well:
  25.  
  26.     NOTE: If you'd like to SKIP the following sections and get right to the
  27.           ANSI-meat portion of this document, search for STARTING WITH ANSI!
  28.                                                          ~~~~~~~~~~~~~~~~~~
  29. RunARexx
  30. ~~~~~~~~
  31.     Copied somewhere on your system, like in DOORS:, you can then create the
  32. following line in your BBSMENU file, to the bottom of Menu # 3:
  33.  
  34.             RUNA, RUNArexx    `31  |  {#0doors:RunARexx}
  35.                                ^      ^
  36.                 Who Can Use RUNA?     Control-Q character.
  37.  
  38.     This command allows you to "test drive" any ARexx program of your choosing
  39. from within CNet proper, just like CNet's internal RUN command can do for any
  40. CNetC programs. You can either type:
  41.  
  42.             CNet: runa<enter>
  43.  
  44.                 - Then type in a <path>filename, or...
  45.  
  46.             CNet: runa <path>filename
  47.  
  48.     Provided the file exists at stated path, it will be executed, however you
  49. will be notified if the file is missing.
  50.  
  51. NewDoor & TestDoor
  52. ~~~~~~~   ~~~~~~~~
  53.     "NewDoor" is an Arexx template to get you started, while "TestDoor" is
  54. a file you can run from anywhere on your system by adding the following to
  55. the end of Menu # 3 in your BBSMENU command:
  56.  
  57.             TEST    `31 | {#0doors:TestDoor}
  58.  
  59.     Whenever you feel like "experimenting" with a new fragment of Arexx code,
  60. copy it into the "TestDoor" script, then type TEST from anywhere on your BBS,
  61. even while inside one of CNet's editors(using the .* or CTRL-C commands)!
  62.  
  63.     These files can act as the "basic framework" for any ARexx creations you
  64. create. They are both virtually identical. The TOP portion of each file holds
  65. the following lines:
  66.  
  67. /**************************************************************************\
  68.       $VER: Program Name, v0.00 (DD-MMM-YY) by Handle of BBS Name!
  69. \**************************************************************************/
  70. options results;signal on SYNTAX;signal on ERROR;signal on IOERR
  71. /*ver=word(sourceline(2),?);a=word(sourceline(2),?);parse var a "("vdate")"*/
  72. tr=transmit;se=sendstring;gc=getchar;gu=getuser;gs=getscratch;mg=maygetchar
  73. a='rexxsupport.library';if ~show('l',a) then if ~addlib(a,0,-30) then exit
  74.  
  75.     You should modify the 2nd and 5th lines above to reflect the name and
  76. version of the file you are creating. If you REMOVE the /* and */ from line
  77. 5, then replace the two "?"'s on the line with the word position of the
  78. version number and date of creation, you'll then have two variables you can
  79. use anywhere in your program when you want to print the VERSION or DATE of
  80. LAST modification. In the above example, you'd replace the first ? with a 4,
  81. because the version number(v0.00) is the FOURTH word on the line. Likewise,
  82. you'd replace the second ? with a 5, as the date(DD-MMM-YY) is the FIFTH word
  83. to appear on line 5. Depending on how you set up line 2, these numbers will
  84. change, so be sure to update them correctly, before attempting to use the
  85. "ver" and "vdate" variables yourself. A line like the following shows you how
  86. these variables could be used in a TRANSMIT variable:
  87.  
  88.             transmit "My Program, "ver", last modified on: "vdate"!"
  89.  
  90.     The 6th and 7th lines listed above offer you a bit more flexability in
  91. your coding. The 6th line creates a series of command "aliases", which you
  92. can then opt to use INSTEAD of typing the entire command. For instance, if a
  93. program you create uses the TRANSMIT command 50 times, the entire word of
  94. TRANSMIT would appear, versus just the two characters TR. So what? Well, when
  95. using TRANSMIT, it's costing you 8 bytes, while if you use TR, it only costs
  96. you 2 bytes. Again, so?!? Use the above example. If TRANSMIT is used 50 times
  97. in your program, and if using TR saves you 6 bytes each time, 50x6=300 bytes.
  98.  
  99.     Now, you continue to do this with the other aliases: SE, GC, GU, GS, and
  100. MG, then do the math, oftentimes this can lead to anywhere from 3K to 10K
  101. savings. You should REMOVE any aliases you are NOT using, and create any NEW
  102. aliases that YOU find helpful. (Keep in mind, however, that if you'll only be
  103. using a given command once or twice, then it won't help to create an alias,
  104. as in these instances, it could result in your program actually taking up
  105. MORE bytes than it really could).
  106.  
  107.     The 7th line simply makes the ARexx Support Library available to you. If
  108. this line is MISSING, and you attempt to use a support command, you'll run
  109. into problems later on. The following commands are stored in this library, so
  110. if your program is NOT using any of these commands, you could DELETE the 7th
  111. line from the NewDoor program:
  112.  
  113.     ALLOCMEM, BADDR, CLOSEPORT, DELAY, DELETE, FORBID, FREEMEM, GETARG,
  114.     GETPKT, MAKEDIR, NEXT, NULL, OFFSET, OPENPORT, PERMIT, RENAME, REPLY,
  115.     SHOWDIR, SHOWLIST, STATEF, TYPEPKT, and WAITPKT.
  116.  
  117.     I'd like to further note that the "dos" type commands listed above, like
  118. DELETE, MAKEDIR, and RENAME are actual ARexx Primitives included as new Arexx
  119. commands, and are NOT the same as if you call one of the DOS commands using
  120. the same name. For example:
  121.  
  122.                             address command "c:delete ram:test"
  123.                     and
  124.                             call DELETE("ram:test")
  125.  
  126.     Both do the same thing, however the ADDRESS command is internal to the
  127. main "rexxsyslib.library", so does NOT make use of the support library, while
  128. using the DELETE() function DOES use the "rexxsupport.library".
  129.  
  130.     Alright, the BOTTOM of both scripts looks like this:
  131.  
  132. exit
  133. CHECK:;if ARG() & ARG(1)~='###PANIC' then return ARG(1)
  134.   getcarrier;if result='TRUE' then if ARG() then return ARG(1);else return
  135.   /* Place any "cleanup" or "reenable" code here, before exiting! */
  136.   logentry 'Lost Carrier!!';bufferflush;exit
  137. SYNTAX:;ERROR:;IOERR:;e1='n1 Error: 'rc' ('errortext(rc)')'
  138.   e2='  Line: 'left(sigl,4)'File:';gu 1311992;a=result;gu 1311960
  139.   b=result;c='"'a||b', 'ver'"';e2=e2' 'c;tr e1;tr e2;logentry e1
  140.   logentry e2;e=translate(sourceline(sigl),"\{","");do while e~=''
  141.   e3='Source: 'left(e,37);tr e3;logentry e3;e=substr(e,38);end;bufferflush
  142. /**************************************************************************\
  143. \****************************************** BBS Name (AAA)/PPP-SSSS *******/
  144.  
  145.     The CHECK: routine is the latest "loss of carrier" check routine that
  146. I've been using. To use the routine, simple CALL it whenever you want to
  147. check for carrier, preferably whenever you're awaiting input from the user,
  148. as in this example:
  149.  
  150.         sendstring "Do what now? " ; getchar ; a=result ; call CHECK
  151.  
  152.     You don't have to go OVERBOARD with your usage of this command, but you
  153. DO want to make sure you include it anywhere that might put the user in a
  154. dead-lock loop(for instance, if you're sking the user to hit 1, 2, or 3, and
  155. if your program will continually ask for one of these keys UNTIL one of them
  156. has been pressed, if the user loses carrier at this prompt, the script will
  157. put itself into a "dead-lock" and you'll have a serious problem.
  158.  
  159.     While creating scripts, if you discover a script that IS in a dead-lock,
  160. there's a program called HI, located in the "Sys:Rexxc/" directory that you
  161. can use to HALT or STOP the Arexx program, however further note that using
  162. this command halts ALL currently running ARexx programs, so if users on other
  163. ports are also using ARexx programs, they'll be kicked out of THEIR programs
  164. as well.
  165.  
  166.     Lastly, note the comment line in the CHECK: routine:
  167.  
  168. /* Place any "cleanup" or "reenable" code here, before exiting! */
  169.  
  170.     If there is any DATA that would need to be saved in order to save the
  171. integrity of what the user was doing, then place calls to your SAVE routines
  172. within this routine as well. Also, if your program MODIFIES one of the user's
  173. settings(for instance, if it turns the MORE mode OFF or MUFFLES the user from
  174. all other users), then be sure to REVERSE the process in this routine as well,
  175. so that if a user was NOT muffled when going INTO your program, and they lose
  176. carrier, the next time they log on, they should STILL NOT be muffled.
  177.  
  178.     The SYNTAX:;ERROR:;IOERR: routine is the latest error-check routine I've
  179. been using myself, and is actually quite powerful in itself. Not only will
  180. the user(or you) be alerted as soon as a "capturable" error has occurred, but
  181. the exact same message will be appended to either your "calls" log, or an
  182. "ARexxSays" log, if you have one defined. The format of the output is such
  183. that it will look as readable as possible when presented in the log. All MCI
  184. commands located on the line are changed to their \{ non-destructive states,
  185. so you can be sure to see the line as it would appear if you were editing it
  186. in a text editor.
  187.  
  188.     The comment lines at the bottom of the listing are included only as a
  189. means of insuring the entire file is intact. You can put your BBS's name in
  190. this comment field if you so wish. 
  191.  
  192.     When using the "NewDoor" file, train yourself to do the following:
  193.  
  194. 1. Load the "NewDoor" file into your text editor.
  195. 2. Change the 2nd and 5th lines as needed.
  196. 3. Now SAVE AS the file as the NAME you'd like to give your creation.
  197. 4. NOW start creating your coding.
  198.  
  199.     This way, you won't discover later on that you no longer HAVE the NewDoor
  200. template to use, because it was morphed into your latest ARexx creation. If
  201. using a Dock-type program, like Tool Manager, you can even opt to create an
  202. instant way to launch both of these programs. For me, because I create LOTS
  203. of different programs, I have them as buttons on a "Programming Dock" on my
  204. WorkBench screen, so creating a NEW program, or testing some new theory is
  205. only a mouse-click away!
  206.  
  207. -----------------------------------------------------------------------------
  208. STARTING WITH ANSI!
  209. ~~~~~~~~~~~~~~~~~~
  210.    Let's start with a look at the Amiga Keyboard. It is possible to capture
  211. keypresses from NUMEROUS additional keys, besides the number and letter keys.
  212. This includes the cursor-arrow keys, the escape key, the backspace key, the
  213. delete key, the enter/return key, the tab key, as well as any/all qualified
  214. keystrokes(those gotten while first holding SHIFT, CTRL, ALT, or a combination
  215. of these).
  216.  
  217.    Among those keystrokes NOT able to be "caught" by ARexx include the ten
  218. function keys(and their qualified states), the help key, the caps lock key,
  219. and any qualified keystrokes using the left or right Amiga Command keys.
  220.  
  221.    The Numeric Keypad to the right of the main keyboard maps to the same
  222. keystrokes as those keys shown on the face of each key. (Meaning the 7 acts
  223. the same as a 7 on the main keyboard, however the `home' function cannot be
  224. mapped to it's own value through Arexx, nor can any of the other `fronts').
  225.  
  226.    For our first look at ARexx and ANSI, let's explore the keyboard. Type or
  227. copy the following into the included "TestDoor" script, then use the TEST 
  228. command to execute the script:
  229.  
  230. START:
  231.   se "Press any key now(press Q to quit): "
  232.   gc ; k=result ; tr k
  233.   if k="Q" then exit
  234.  signal START
  235.  
  236.    The above script will loop forever, until such a time as you press the "Q"
  237. key on your keyboard. After using it for a bit, you'll notice that there are
  238. many keys you can press which return visual(printable) results, which can all
  239. be used within your ARexx creations.
  240.  
  241.    While still running the above program, try pressing the following keys:
  242.  
  243.             enter, tab, backspace, ctrl-q, ctrl-s, ctrl-y
  244.  
  245.    There are others as well, but you get my drift, right? :-) These keystrokes
  246. DID return a value(as shown by the prompt advancing a line), however in their
  247. current state, the returned results are unusable. Now try pressing the cursor
  248. arrow keys, specifically noting what happens to the prompt(especially the next
  249. one printed after pressing an arrow key). Did you notice the "P" in the text
  250. for the prompt was suppressed? Remember this behavior for a bit. Lastly, try
  251. typing an "A" on the keyboard. Did it print an UPPER or lowercase letter? See
  252. if you can get it to print the opposite case letter.
  253.  
  254.    As shown above, the initial script "sorta" works, and in fact, works GREAT
  255. for some applications, but not for others, so let's change the script a bit.
  256. Try copying the following into your "TestDoor" script ABOVE the script we
  257. were working with earlier:
  258.  
  259. START2:
  260.   se "Press any key now(press Q to quit): "
  261.   do until k~="NOCHAR" ; mg ; k=result ; end
  262.   tr c2d(k) ; if k="q" then exit
  263.  signal START2
  264.  
  265.    After running this one for awhile, you'll notice somthing VERY strange.
  266. Instead of seeing the printable characters you WANTED, you're seeing NUMBERS,
  267. nothing but NUMBERS. Now, before you get in a tizzy, try those "bad" keys
  268. again. Remember:
  269.  
  270.             enter, tab, backspace, ctrl-q, ctrl-s, ctrl-y
  271.  
  272.    Also, see what happens when you press "A", "SHIFT-A", "CTRL-A", etc. I'm
  273. hoping you're noticing that even though it's NUMBERS being returned, they are
  274. all UNIQUE from each other.
  275.  
  276.    Now, try typing the cursor arrows again. Notice the output this time is
  277. NUMBERS again, but did you ALSO notice that it printed THREE numbers, instead
  278. of ONE, as all the other keystokes did? Are you seeing what's happening yet?
  279.  
  280.    No? Would it help if I told you that all these NUMBERS it's printing right
  281. now are the ASCII equivalents of the actual characters? If you were to look
  282. through an ASCII chart, here's what you'd find for the three numbers that are
  283. printed when you press the UP cursor arrow:
  284.  
  285. Press any key now(press Q to quit): 27      <--- An ESCape code.
  286. Press any key now(press Q to quit): 91      <--- An open bracket ([).
  287. Press any key now(press Q to quit): 65      <--- A capital letter A.
  288.  
  289.                     In other words:   ESC [ A
  290.  
  291.    Does THAT look a bit more familiar?!? hehe I should hope so. You'll notice
  292. similar strings of numbers for the other arrows:
  293.  
  294.                     27-91-66    <--- DOWN  cursor arrow.
  295.                     27-91-67    <--- RIGHT cursor arrow.
  296.                     27-91-68    <--- LEFT  cursor arrow.
  297.  
  298.    Before we continue, try pressing the ESCape key while running the script:
  299.  
  300. Press any key now(press Q to quit): 27
  301.  
  302.    Note that it returns the same 27 that was also used in the cursor keystroke
  303. lists. So, what does all this MEAN? Well, it means that it's possible for us
  304. to capture these keystrokes, however depending on WHICH keystrokes we want,
  305. we have to go about GETTING them through different means.
  306.  
  307.    Let's take a look at a script with a bit more meat. Copy the following to
  308. your "TestDoor" script ABOVE the START2: routine we just finished with:
  309.  
  310. KEYS1:
  311.   tr "Press some keys now..."
  312.   do forever until k="q"
  313.     mg ; k=result ; kk="" ; if k="NOCHAR" then iterate
  314.     if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  315.     select
  316.       when c2d(k)=27 & kk="NOCHAR" then tr "You pressed the ESCape key..."
  317.       when kk="A"     then tr "You pressed the UP cursor arrow..."
  318.       when kk="B"     then tr "You pressed the DOWN cursor arrow..."
  319.       when kk="C"     then tr "You pressed the RIGHT cursor arrow..."
  320.       when kk="D"     then tr "You pressed the LEFT cursor arrow..."
  321.       when c2d(k)=13  then tr "You pressed the ENTER key..."
  322.       when c2d(k)=9   then tr "You pressed the TAB key..."
  323.       when c2d(k)=127 then tr "You pressed the DELETE key..."
  324.       when c2d(k)=8   then tr "You pressed the BACKSPACE key..."
  325.       when c2d(k)=32  then tr "You pressed the SPACEBAR key..."
  326.       otherwise tr "You pressed the "k" key..."
  327.     end
  328.   end
  329.  exit
  330.   
  331.    The above routine will successfully capture ANY of the "available" keys.
  332. You'll notice that the MAYGETCHAR command has been used solely in the routine,
  333. however it could be slightly rewritten to use the GETCHAR command instead:
  334.  
  335. KEYS2:
  336.   tr "Press some keys now..."
  337.   do forever until k="Q"
  338.     gc ; k=result ; kk="" ; if c2d(k)=27 then do 2 ; gc ; kk=result ; end
  339.     select
  340.       when c2d(k)=27 & kk="" then tr "You pressed the ESCape key..."
  341.       when kk="A"     then tr "You pressed the UP cursor arrow..."
  342.       when kk="B"     then tr "You pressed the DOWN cursor arrow..."
  343.       when kk="C"     then tr "You pressed the RIGHT cursor arrow..."
  344.       when kk="D"     then tr "You pressed the LEFT cursor arrow..."
  345.       when c2d(k)=13  then tr "You pressed the ENTER key..."
  346.       when c2d(k)=9   then tr "You pressed the TAB key..."
  347.       when c2d(k)=127 then tr "You pressed the DELETE key..."
  348.       when c2d(k)=8   then tr "You pressed the BACKSPACE key..."
  349.       when c2d(k)=32  then tr "You pressed the SPACEBAR key..."
  350.       otherwise tr "You pressed the "k" key..."
  351.     end
  352.   end
  353.  exit
  354.  
  355.    You'll notice the KEYS2 routine is a bit shorter than the KEYS1 routine,
  356. however KEYS2 lacks the ability to map UPPER versus lowercase letter keys.
  357. The MAYGETCHAR command returns the ACTUAL key pressed, which means "a" is
  358. returned if you press the "a" key, while "A" is returned if "SHIFT-A" was
  359. pressed.
  360.  
  361.    Another nice advantage to using MAYGETCHAR is that it means precisely what
  362. it's name implies, the Amiga MAY get a character, or it MAY NOT. If a key was
  363. NOT caught, MAYGETCHAR returns the text string "NOCHAR". Well, you're most
  364. probably thinking, "So what?", right? Well, not HAVING to wait for a keypress
  365. can come in REAL handy when writing programs. For instance, let's take a GAME
  366. for an example. I'm thinking of the game Tetris. If you opt NOT to move one
  367. of the shapes to the left or the right, and you opt NOT to rotate the shape,
  368. what happens to the shape? Does it just sit there WAITING for you to tell it
  369. what you want it to do? Yeah, I wish! No, it continues to move DOWN the game
  370. screen. It's this same MAYGETCHAR type of operation that allows a game like
  371. Tetris to do that:
  372.  
  373.         SHAPE:
  374.           - Display the shape.
  375.         MOVE:
  376.           - Did user hit LEFT or RIGHT?
  377.             - Yes - then move the shape...
  378.             - No - then continue...
  379.           - Did user ROTATE the shape?
  380.             - Yes - then rotate the shape...
  381.             - No - then continue...
  382.           - Move the shape DOWN one line!
  383.           - Did shape hit bottom yet?
  384.             - Yes - then go to SHAPE:
  385.             - No - then go back to MOVE:
  386.  
  387.    What's more, you could also have things like a SCORE being updated while
  388. waiting for the keystrokes. You could display the NEXT shape or two, etc.
  389. without having to WAIT for a keystroke.
  390.  
  391.    Now, you have to be a BIT careful here, as you don't want to spend TOO
  392. MUCH time doing other things, else you'll lose the seamless flow to the
  393. end result you're looking to accomplish.
  394.  
  395.    Alright, so we know HOW to get the characters from the keyboard, but how
  396. do we then create an ARexx routine to USE these characters? Let's take yet
  397. another ARexx routine. Copy this one ABOVE the KEYS1 (or KEYS2) routine you
  398. were last working with, then run the "TestDoor" script again:
  399.  
  400.     tr "f1.--.--.--.--.--.--.--.--.--.--."
  401.   do 9;tr "|  |  |  |  |  |  |  |  |  |  |"
  402.        tr "|--+--+--+--+--+--+--+--+--+--|";end
  403.        tr "|  |  |  |  |  |  |  |  |  |  |"
  404.        tr "`--^--^--^--^--^--^--^--^--^--'"
  405.                   row=1 ; col=1
  406. MOVE:
  407.   se ""row*2";"col*3-1"H"
  408.   gc ; k=result ; kk="" ; if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  409.   if c2d(k)=27 & kk="NOCHAR" then do ; se "1HExiting..." ; exit ; end
  410.   if c2d(k)=13 then do ; se "1HRow: "row", Column: "col ; exit ; end
  411.   if kk="A" & row>1  then row=row-1
  412.   if kk="B" & row<10 then row=row+1
  413.   if kk="C" & col<10 then col=col+1
  414.   if kk="D" & col>1  then col=col-1
  415.  signal MOVE
  416.  
  417.    This routine starts by printing a simple 10x10 grid, with an Ascii Frame
  418. around it. The MOVE: routine uses the same techniques discussed above, with
  419. the addition of two variables, "row" and "col". These variables have their
  420. values changed, dependent upon which cursor-arrow keys you press. This is
  421. evident in the program by the cursor moving around within the grid. If we
  422. press ESC, we can EXIT the program, but if we press ENTER, we exit as well
  423. as being told WHICH row and column we were IN before we left.
  424.  
  425.    This is a fairly simple grid technique with some limitations. For one, it
  426. uses finite borders. This means that once we reach one of the borders, that's
  427. as far as the current script will allow us to go. With some slight changes to
  428. the four "if kk=..." lines, we can make this movement more powerful:
  429.  
  430.   if kk="A" then do ; row=row-1 ; if row<1 then row=10 ; end
  431.   if kk="B" then do ; row=row+1 ; if row>10 then row=1 ; end
  432.   if kk="C" then do ; col=col+1 ; if col>10 then col=1 ; end
  433.   if kk="D" then do ; col=col-1 ; if col<1 then col=10 ; end
  434.  
  435.    With the above changes, the script will allow the cursor to wrap around
  436. the borders, which allows for a bit more freedom of movement.
  437.  
  438.    Another problem with the script occurs if we give some thought as to WHO
  439. might be using the program. Some IBM and Amiga users do not have separate
  440. arrow keys on their keyboards. These users rely on using the Numeric Keypad's
  441. arrow keys, which reside on the 2, 4, 6, and 8 keys. We could further modify
  442. the above lines to take these people into consideration as well:
  443.  
  444.   if k="8" | kk="A" then do ; row=row-1 ; if row<1 then row=10 ; end
  445.   if k="2" | kk="B" then do ; row=row+1 ; if row>10 then row=1 ; end
  446.   if k="6" | kk="C" then do ; col=col+1 ; if col>10 then col=1 ; end
  447.   if k="4" | kk="D" then do ; col=col-1 ; if col<1 then col=10 ; end
  448.  
  449.    Not too much extra to satisfy these users, huh? Well, what else could the
  450. "little script that could" use? How about getting rid of the cursor? If we
  451. change the first few lines of the MOVE: routine to use the MAYGETCHAR command,
  452. instead of the GETCHAR command, we can solve this problem:
  453.  
  454. MOVE:
  455.   se ""row*2";"col*3-1"H"
  456.   do until k~="NOCHAR" ; mg ; k=result ; end ; kk=""
  457.   if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  458.  
  459.    However, if you try these changes, you'll notice another problem, as there
  460. is no way of knowing WHERE you are, so we need a VISIBLE character to act as
  461. our prompt character. This can be accomplished by adding 1 character to the
  462. first line of the MOVE: routine:
  463.  
  464.   se ""row*2";"col*3-1"H>"
  465.  
  466.    Note the addition of the > character as the second last character on the
  467. line above. This gives us a better looking cursor over the "big block", but
  468. because this is a PRINTABLE character, you'll notice a trail of >'s follow
  469. you as you traverse the grid. To fix this problem, we need to add one line
  470. right above those "if kk=..." lines, like this:
  471.  
  472.   tr ""row*2";"col*3-1"H "
  473.  
  474.    Note that in the above line, a SPACE appears where the > appeared in the
  475. line that printed the prompt. What we're doing is using the ANSI positioning
  476. codes to print the cursor, print a space OVER the cursor, modify the position
  477. of the cursor, then reprint the cursor. Here's what the entire routine should
  478. now look like:
  479.  
  480.     tr "f1.--.--.--.--.--.--.--.--.--.--."
  481.   do 9;tr "|  |  |  |  |  |  |  |  |  |  |"
  482.        tr "|--+--+--+--+--+--+--+--+--+--|";end
  483.        tr "|  |  |  |  |  |  |  |  |  |  |"
  484.        tr "`--^--^--^--^--^--^--^--^--^--'"
  485.                   row=1 ; col=1
  486. MOVE:
  487.   se ""row*2";"col*3-1"H>"
  488.   do until k~="NOCHAR" ; mg ; k=result ; end ; kk=""
  489.   if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  490.   if c2d(k)=27 & kk="NOCHAR" then do ; se "1HExiting..." ; exit ; end
  491.   if c2d(k)=13 then do ; se "1HRow: "row", Column: "col ; exit ; end
  492.   tr ""row*2";"col*3-1"H "
  493.   if k="8" | kk="A" then do ; row=row-1 ; if row<1 then row=10 ; end
  494.   if k="2" | kk="B" then do ; row=row+1 ; if row>10 then row=1 ; end
  495.   if k="6" | kk="C" then do ; col=col+1 ; if col>10 then col=1 ; end
  496.   if k="4" | kk="D" then do ; col=col-1 ; if col<1 then col=10 ; end
  497.  signal MOVE
  498.  
  499.    Well, there you have it! It's actually not that hard to do. Now, there are
  500. some "extras" you might want to toss into a routine like the above. Perhaps
  501. you'd like to be able to "drop" something where the cursor was located, maybe
  502. when the user presses their ENTER keys or something. Again, nothing more than
  503. a slight modification to an existing line above, in this case the line that
  504. starts with "if c2d(k)=13 then..."
  505.  
  506.   if c2d(k)=13 then do ; se ""row*2";"col*3"H#" ; signal MOVE ; end
  507.  
  508.    The above change will allow you to place a # character to the RIGHT of the
  509. > prompt, whenever you press your ENTER key. Note, however, that once the # is
  510. placed, it's there for GOOD. To REMOVE it, you'd have to either define a 2nd
  511. keystroke to remove/lift the piece, or else create an arrayed variable that
  512. would house the contents of each "spot" within the grid.
  513.  
  514.    I'll shy away from pursuing that any farther, as that's getting a bit more
  515. into Game Theory, instead of ANSI coding, but you get the general idea!
  516.  
  517.    Alright, so what ELSE is there to ANSI coding in ARexx? Well, how about the
  518. creation of an AnsiARexx editor, which is used in exactly the same way as one
  519. of CNet's VDE editors? This is yet another feat for the serious ANSI-ARexx
  520. coder. Let's take a look at a fairly simple AnsiARexx editor, which can be
  521. used to modify your mailing address:
  522.  
  523.   gu 3 ; realname=result  ; gu 6 ; street=result
  524.   gu 4 ; citystate=result ; gu 5 ; zip=result
  525.   kb.1="     Real Name:"  ; kb.2="Street Address:"
  526.   kb.3="   City, State:"  ; kb.4="      Zip Code:"
  527.   tr "f1z4c7 Simple AnsiARexx VDE Editor z0n1"
  528.   tr "z4c7     Real Name:z0 c3"realname
  529.   tr "z4c7Street Address:z0 c3"street
  530.   tr "z4c7   City, State:z0 c3"citystate
  531.   tr "z4c7      Zip Code:z0 c3"zip
  532.   kb=1 ; kbt=4
  533. EDIT:
  534.   se ""kb+2";1Hz7c4"kb.kb"z0q1"
  535.   do until k~="NOCHAR" ; mg ; k=result ; end ; kk=""
  536.   if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  537.   if c2d(k)=27 & kk="NOCHAR" then do ; tr "1HExiting..." ; exit ; end
  538.   se ""kb+2";Hz4c7"kb.kb"z0"
  539.   if kk="A" then do ; kb=kb-1 ; if kb<1 then kb=kbt ; end
  540.   if kk="B" then do ; kb=kb+1 ; if kb>kbt then kb=1 ; end
  541.  signal EDIT
  542.  
  543.    The above code initially reads in your current values, creates a set of
  544. Ansi buttons(the kb. array), as well as setting up two pointers, kb, which
  545. is used to specify which button will be initially highlighted, and kbt which
  546. tells the script the total number of buttons defined. The EDIT: routine uses
  547. the same techniques we've already seen, except instead of printing the one
  548. character > prompt, we're printing the kb. button. Only two cursor keys have
  549. been defined, as there's only one column of data. The UP and DOWN arrows can
  550. be used to move the highlighted button up or down and the ESCape key will
  551. exit the editor.
  552.  
  553.    To actually EDIT the data, we need to define what the ENTER key should do,
  554. based on the value of the kb variable, as that will point at WHICH button was
  555. highlighted when you pressed ENTER. The following code is placed BELOW the
  556. `if kk="B"...' line above:
  557.  
  558.   if c2d(k)=13 then do
  559.     if kb=1 then do ; se ""kb+2";17Hr1c3L1305640 #"realname"}I20 34}"
  560.       gu 70;realname=result;signal EDIT;end
  561.     if kb=2 then do ; se ""kb+2";17Hr1c3L1305640 #"street"}I20 30}"
  562.       gu 70;street=result;signal EDIT;end
  563.     if kb=3 then do ; se ""kb+2";17Hr1c3L1305640 #"citystate"}I20 22}"
  564.       gu 70;citystate=result;signal EDIT;end
  565.     if kb=4 then do ; se ""kb+2";17Hr1c3L1305640 #"zip"}I20 10}"
  566.       gu 70;zip=result;signal EDIT;end
  567.   end
  568.  
  569.    As you can see, the above bit of code is almost as big as the EDIT: routine
  570. itself. I didn't say it would be short! hehe I'm using the {L } MCI command to
  571. load the data into the "line input buffer". The {I20 } MCI command is used to
  572. get a line of input from the user. The "20" is the MCI Environment setting,
  573. and actually stands for 4+16. The 4 means to start with the line input buffer,
  574. and the 16 means to make the first character of every word entered UPPER case.
  575.  
  576.    As shown, the above is a 90% duplicate of the CNetC VDE editors. CNet's
  577. internal VDE editors do two more things: they show the max length of input
  578. possible, while editing a field, and they utilize a "smart" save feature. The
  579. following is the complete version of this editor:
  580.  
  581.   gu 3 ; realname=result  ; gu 6 ; street=result
  582.   gu 4 ; citystate=result ; gu 5 ; zip=result
  583.   kb.1="     Real Name:"  ; kb.2="Street Address:"
  584.   kb.3="   City, State:"  ; kb.4="      Zip Code:"
  585.   tr "f1z4c7 Simple AnsiARexx VDE Editor z0n1"
  586.   tr "z4c7     Real Name:z0 c3"realname
  587.   tr "z4c7Street Address:z0 c3"street
  588.   tr "z4c7   City, State:z0 c3"citystate
  589.   tr "z4c7      Zip Code:z0 c3"zip
  590.   kb=1 ; kbt=4 ; save=0
  591. EDIT:
  592.   se ""kb+2";1Hz7c4"kb.kb"z0q1"
  593.   do until k~="NOCHAR" ; mg ; k=result ; end ; kk=""
  594.   if c2d(k)=27 then do 2 ; mg ; kk=result ; end
  595.   if c2d(k)=27 & kk="NOCHAR" then signal SAVE
  596.   se ""kb+2";Hz4c7"kb.kb"z0"
  597.   if kk="A" then do ; kb=kb-1 ; if kb<1 then kb=kbt ; end
  598.   if kk="B" then do ; kb=kb+1 ; if kb>kbt then kb=1 ; end
  599.   if c2d(k)=13 then do
  600.     if kb=1 then do ; se ""kb+2";17Hz3L1305640 #"realname"}s"
  601.       se left("",34)"uz3c4I20 34}";gu 70;a=result;save=(a~=realname)
  602.       se "z0c3u"left(a,34);realname=a;signal EDIT;end
  603.     if kb=2 then do ; se ""kb+2";17Hz3L1305640 #"street"}s"
  604.       se left("",30)"uz3c4I20 30}";gu 70;a=result;save=(a~=street)
  605.       se "z0c3u"left(a,30);street=a;signal EDIT;end
  606.     if kb=3 then do ; se ""kb+2";17Hz3L1305640 #"citystate"}s"
  607.       se left("",22)"uz3c4I20 22}";gu 70;a=result;save=(a~=citystate)
  608.       se "z0c3u"left(a,22);citystate=a;signal EDIT;end
  609.     if kb=4 then do ; se ""kb+2";17Hz3L1305640 #"zip"}s"
  610.       se left("",10)"uz3c4I20 10}";gu 70;a=result;save=(a~=zip)
  611.       se "z0c3u"left(a,10);zip=a;signal EDIT;end
  612.   end
  613.  signal EDIT
  614. SAVE:
  615.   if save=0 then tr "1HNo changes made... Exiting..." 
  616.    else tr "1HChanges Made! Data automatically SAVED, then exit..."
  617.  exit
  618.  
  619.    I won't give you the actual SAVE coding, as I want this to be an example
  620. only. You should be able to create the SAVE code yourself, if you actually
  621. WANTED to use this editor. :-)
  622.  
  623.     Well, that's enough of the "heavy duty" Ansi Coding. For our last example,
  624. lets have some fun on the screen itself by creating a "kaleidoscope" type of
  625. program using ANSI. Copy the following ABOVE the last routine you pasted into
  626. the TestDoor script:
  627.  
  628. a=random(,,time("s")) ; se "f1Hello"
  629. gu 27 ; cols=result ; gu 1100468 ; rows=result
  630. do forever until k="q" ; mg ; k=result
  631.   row=random(1,rows) ; col=random(1,cols-1)
  632.   co=substr("0123456789abcdef",random(1,16),1)
  633.   char=d2c(random(32,190))
  634.   se ""row";"col"Hc"co||char
  635. end ; tr "1HGood Bye!"
  636. exit
  637.  
  638.     The above will go on forever, until you press the "Q" key on the keyboard.
  639. Being completely random, it produces a mish-mash design on the screen. Here's
  640. another that looks a bit more like the kaleidoscopes you may remember:
  641.  
  642. a=random(,,time("s")) ; se "f1Hello"
  643. gu 27 ; cols=result ; gu 1100468 ; rows=result
  644. do forever until k="q" ; mg ; k=result
  645.   row=random(1,rows%2) ; col=random(2,cols%2)-1
  646.   co=substr("0123456789abcdef",random(1,16),1)
  647.   char=d2c(random(161,255))
  648.   se ""row";"col"Hc"co||char
  649.   se ""row";"cols-col"Hc"co||char
  650.   se ""rows-row";"col"Hc"co||char
  651.   se ""rows-row";"cols-col"Hc"co||char
  652. end ; tr "1HGood Bye!"
  653. exit
  654.  
  655.     The above version chops the visible screen into 4 quadrants, then mirrors
  656. the chosen character into each quadrant as a certain distance from the center
  657. of the screen to create the design.
  658.  
  659.     Lastly, try this version:
  660.  
  661. a=random(,,time("s")) ; se "f1Hello"
  662. gu 27 ; cols=result ; gu 1100468 ; rows=result
  663. do forever until k="q" ; mg ; k=result
  664.   row=random(1,(rows%2)-5) ; col=random(1,(cols%2)-5)-1
  665.   co=substr("0123456789abcdef",random(1,16),1)
  666.   char=d2c(random(161,255)) ; a=random(1,5)
  667. do i=1 to a
  668.   se ""row+i";"col+i"Hc"co||char
  669.   se ""row+i";"cols-col-i"Hc"co||char
  670.   se ""rows-row-i";"col+i"Hc"co||char
  671.   se ""rows-row-i";"cols-col-i"Hc"co||char
  672. end i
  673. end ; tr "1HGood Bye!"
  674. exit
  675.  
  676.     By introducing a second loop to the action, actual strings of characters
  677. are printed to the screen, instead of individual characters. This idea could
  678. be taken even further, perhaps by changing the direction of the string, or
  679. producing strings that weren't necessarily straight lines, but perhaps ones
  680. that curved, etc. open up a plethora of different possibilities.
  681.  
  682.     Well, I've tried to think of as many different ways as possible where you
  683. might use ANSI coding with your ARexx commands to further enhance the programs
  684. you create. It is my sincere hope that some or all of the above material will
  685. prove useful for you in the things that you create.
  686.  
  687.     If you'd like to take any of the previous examples to the next, logical
  688. step, but still aren't quite sure how to proceed, feel free to contact me with
  689. any questions you may have. I will definately have wanted you to have read
  690. through this document, and have at least gotten some sort of framework laid
  691. out, but will gladly give you the next building block towards your finished
  692. creation! :-)
  693.  
  694.     Here's how I may be contacted:
  695.  
  696.         Through Internet EMail:     dotoran@bluemoon.net
  697.  
  698.         Through World Wide Web:     http://www.bluemoon.net/~dotoran
  699.  
  700.        Through FidoNet Network:     dotoran@1:260/121.0
  701.  
  702.          Through CLink Network:     dotoran@911:6840/2.0
  703.  
  704.             Through Snail Mail:     David M. Weeks
  705.                                     318 Woodside Avenue
  706.                                     Buffalo, NY 14220-2015
  707.                                     ATTN: Dotoran
  708.  
  709.     If you feel what you need to ask could be of public interest, you can post
  710. a message, addressed to Dotoran, to one of the following messaging echoes:
  711.  
  712.         The CNET and CNET_BBS message echoes of FidoNet.
  713.  
  714.         The CLINKCNETAMIGA and CLINKCNETPROG message echoes of CLink.
  715.  
  716.         The "CNet Mailing List" on the Internet.
  717.  
  718. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  719.         Created using CED by Dotoran of Frontiers BBS (716)/823-9892!
  720. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  721.